// #include<iostream>
// #include<cstdlib>
// #include<unistd.h>
// using namespace std;
// #include<sys/types.h>
// #include<strings.h>
// #include<sys/socket.h>
// #include<netinet/in.h>
// #include<arpa/inet.h>
// #include<cstring>
// #include<string>

// void Usage(string proc)
// {
//     cout << "Usage: " << proc << " serverip serverport\n" << endl;
// }
 

// //./udpclient serverip serverport 
// int main(int argc, char* argv[])
// {
//     if (argc != 3)
//     {
//         Usage(argv[0]);
//         exit(1);
//     }
//     //
//     string serverip = argv[1];
//     uint16_t serverprot = stoi(argv[2]);
    
//     struct sockaddr_in server;

//     bzero(&server, sizeof(server));
//     server.sin_family = AF_INET;
//     server.sin_port = htons(serverprot);
//     server.sin_addr.s_addr = inet_addr(serverip.c_str());
    
//     socklen_t serlen = sizeof(server);


        
//     int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
//     if (sockfd < 0)
//     {
//         cout << "socker error" << endl; 
//         return 1;
//     }

//     //客户端要绑定吗？ 首先， 客户端， 一定要绑定。 也就意味着， 客户端一定要有子的id和端口。 
//     //只不过， 不需要用户显示的bind。一般由操作系统自由随机选择！一个端口号只能由一个程序绑定。 一个程序却能够绑定多个端口号。 
//     //对于server， client都是如此。     
//     //客户端的端口号是几其实不重要， 只要能保证唯一性即可。 

//     //系统什么时候给我bind呢？首次发送数据的时候。

//     string message;
//     char buffer[1024];
//     while(true)
//     {   
//         cout << "please Enter@:" << endl;
//         getline(cin, message);  
//         //1.数据   2.给谁发

//         sendto(sockfd, message.c_str(), message.size(), 0,  (struct sockaddr*)&server, serlen);
//         cout << "yes" << endl;

//         //接收数据
//         sockaddr_in temp;
//         socklen_t socklen;
//         ssize_t sz = recvfrom(sockfd, (void*)buffer, sizeof(buffer) - 1, 0, (sockaddr*)&temp, &socklen); //sockfd其实就是网卡的pid
        
//         if(sz > 0)
//         {
//             buffer[sz] = 0;
//             cout << buffer << endl;
//         }
//     }
    

//     close(sockfd);
//     return 0;
// }



// #include<iostream>
// #include<cstdlib>
// #include<unistd.h>
// using namespace std;
// #include<sys/types.h>
// #include<strings.h>
// #include<sys/socket.h>
// #include<netinet/in.h>
// #include<arpa/inet.h>
// #include<cstring>
// #include"Log.hpp"
// #include<string>
// Log lg;


// //./udpclient serverip serverport 
// int main(int argc, char* argv[])
// {
//     if (argc != 3)
//     {
//         cout << "has return" << endl;
//         return 1;
//     }
//     //
//     string serverip = argv[1];
//     uint16_t serverprot = stoi(argv[2]);
    
//     //创建套接字
//     struct sockaddr_in server;
//     bzero(&server, sizeof(server));
//     server.sin_family = AF_INET;
//     server.sin_port = htons(serverprot);
//     server.sin_addr.s_addr = inet_addr(serverip.c_str());
//     socklen_t serlen = sizeof(server);

//     int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
//     if (sockfd < 0)
//     {
//         cout << "socker error" << endl; 
//         return 1;
//     }


//     string message;
//     char buffer[1024];
//     while(true)
//     {   

//         cout << "please Enter@:" << endl;
//         getline(cin, message);  
        
//         //发送数据
//         sendto(sockfd, message.c_str(), message.size(), 0,  (struct sockaddr*)&server, serlen);

//         //接收数据
//         sockaddr_in temp;
//         socklen_t len;
//         string info;
//         ssize_t s = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&temp, &len);
//         if (s < 0)
//         {
//             lg(Error, "recv error, error: %d, strerror: %s", errno, strerror(errno));
//             continue;
//         }
//         buffer[s] = 0;
//         info = buffer;
//         cout << info << endl;
//     }
    

//     close(sockfd);
//     return 0;
// }


#include<iostream>
using namespace std;
#include<string>
#include<sys/types.h>
#include"Log.hpp"
#include<sys/socket.h>
#include<pthread.h>
#include<arpa/inet.h>
#include<string.h>
#include<netinet/in.h>
Log lg;


class ThreadData
{
public:
    sockaddr_in server;
    int sockfd;
};

void* recv_message(void* args)
{
    char buffer[1024];
    ThreadData* td = static_cast<ThreadData*>(args);    
    while (true)
    {
        //接收数据
        sockaddr_in temp;
        socklen_t len;
        string info;
        ssize_t s = recvfrom(td->sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&temp, &len);
        if (s < 0)
        {
            lg(Error, "recv error, error: %d, strerror: %s", errno, strerror(errno));
            continue;
        }
        buffer[s] = 0;
        info = buffer;
        cout << info << endl;
    }

}

void* send_message(void* args)
{
    ThreadData* td = static_cast<ThreadData*>(args);
    string message;
    while (true)
    {
        getline(cin, message);  //获取数据
        //发送数据
        sendto(td->sockfd, message.c_str(), message.size(), 0, (sockaddr*)&td->server, sizeof(td->server));

    }
}

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        cout << "Client server" << endl;
    }

    //先拿到套接字的参数
    string serverip = argv[1];
    uint16_t serverport = stoi(argv[2]);

    ThreadData td;

    //创建套接字与打开网卡
    memset(&td.server, 0, sizeof(td.server));
    td.server.sin_family = AF_INET;
    td.server.sin_port = htons(serverport);
    td.server.sin_addr.s_addr = inet_addr(serverip.c_str());
    td.sockfd = socket(AF_INET, SOCK_DGRAM, 0); //创建文件描述符, 网卡的文件描述符， 网络传输就是使用网络文件描述符找到对应的文件内的数据
    if (td.sockfd < 0)
    {
        lg(Error, "client create sockfd error, errno: %d, strerror: %s", errno, strerror(errno));
        exit(1);
    }

    //创建线程， 然后运行线程， 等待线程
    pthread_t recv, send;
    pthread_create(&recv, nullptr, recv_message, &td);
    pthread_create(&send, nullptr, send_message, &td);

    pthread_join(recv, nullptr);
    pthread_join(send, nullptr);

    close(td.sockfd);
    return 0;
}
